#include <gtk/gtk.h>

#include "serverset.h"
#include "chatapp.h"
#include "chatappwin.h"
#include "msgwin.h"
#include "account.h"
#include <json-glib/json-glib.h>
#include <json-glib/json-gobject.h>

#define MSG_MAX	4096
struct _ChatAppWindow
{
  GtkApplicationWindow parent;
};

typedef struct _ChatAppWindowPrivate ChatAppWindowPrivate;

struct _ChatAppWindowPrivate
{
	GSettings *settings;
	GtkWidget *stack;
	GtkWidget *search;
	GtkWidget *searchbar;
	GtkWidget *searchentry;
	GtkWidget *null;
	GtkWidget *sidebar;
	GtkWidget *words;
	GtkWidget *lines;
	GtkWidget *lines_label;
	//
	GtkWidget *setting;
	GtkWidget *news;
	GtkWidget *home;
	GtkWidget *back;
	GtkWidget *scrolled_box;
	GtkWidget *apps;
	GtkWidget *add;
	GtkWidget *notice;

	//gpointer conn;
};

G_DEFINE_TYPE_WITH_PRIVATE(ChatAppWindow, chat_app_window, GTK_TYPE_APPLICATION_WINDOW);

extern void *server_connect (const char *network, gpointer user_data);
extern const char *account_status[];
static void null_cb (GtkButton *button, gpointer user_data)
{
	ServerSet *win;

	win = server_set_new (user_data);
	g_debug("%s:%d,null:%p cwin:%p\n", __FILE__, __LINE__, win, user_data);
	gtk_window_present (GTK_WINDOW (win));
}
void conn_send(gpointer ptr, const void *data, gsize size)
{
	GSocketConnection *conn = NULL;
	GError *error = NULL;
	GOutputStream *ostream = NULL;

	conn = g_object_get_data(G_OBJECT(ptr), "conn");
	g_debug("%s[%d]conn:%p\n", __FILE__, __LINE__, conn);
	ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn));
	g_output_stream_write(ostream, data, size, NULL, &error);
	if (error) {
		g_print ("%s\n", error->message);
		g_error_free (error);
		goto err;
	} else
		g_debug("%s:%d->----msg:%s\n", __FILE__, __LINE__, (char *)data);
err:
	return;
}
static void msg_cb(GtkButton *button, gpointer user_data)
{
	const char *peer_id = NULL;
	ChatAppWindow *win;
	MsgWindow *msg_win;
	//ChatAppWindowPrivate *priv;
  gpointer conn = NULL;

	win = user_data;
	//priv = chat_app_window_get_instance_private (win);

	conn = g_object_get_data(G_OBJECT(win), "conn");
	msg_win = msg_window_new (user_data);
	peer_id = g_object_get_data(G_OBJECT(button), "peer_id");
	g_object_set_data(G_OBJECT(msg_win), "peer_id", (void *)peer_id);
	g_debug("%s:%d,msg_window:%p,peer_id:%s\n", __FILE__, __LINE__,
			win, peer_id);
	g_object_set_data(G_OBJECT(msg_win), "conn", conn);
	gtk_window_present (GTK_WINDOW (msg_win));
	goto err;
err:
	return;
}
void data_scrolled_add(gpointer ptr, guint8 *msg, gint nread, gpointer user_data)
{
	int i = 0, sum = 0;
	char buf[32] = {0};
	const char *id = NULL, *alias = NULL;
	GtkWidget *scrolled_box = NULL, *button = NULL;
  JsonParser *parser = NULL;
  //JsonGenerator *gen = NULL;
  JsonNode *root = NULL;//, *node = NULL;
  JsonObject *object = NULL;
  GError *error = NULL;
	void *array_data = NULL, *array_unit = NULL;

	scrolled_box = ptr;
	g_debug("%s:%d->scrolled_box:%p\n", __FILE__, __LINE__, scrolled_box);
//remove all child
  GList *children, *next;
  children = gtk_container_get_children(GTK_CONTAINER(scrolled_box));
  next = children;
  while (next) {
    gtk_container_remove(GTK_CONTAINER(scrolled_box), next->data);
    next = g_list_next(next);
  }
  g_list_free(children);
//add child
  parser = json_parser_new ();
  json_parser_load_from_data(parser, (char *)msg, -1, &error);
  root = json_parser_get_root(parser);
  object = json_node_get_object(root);
  if (!object) {
//    json_object_set_string_member(obj_send, "error", "is not json");
    goto err;
  }
	array_data = json_object_get_array_member(object, "data");
	sum = json_array_get_length(array_data);
  char *dup_id = NULL;
	for (i = 1; i < sum; i++) {
		array_unit = json_array_get_array_element(array_data, i);
		id = json_array_get_string_element(array_unit, 0);
    dup_id = g_strdup(id);
		alias = json_array_get_string_element(array_unit, 1);
		snprintf(buf, sizeof(buf), "(%s)%s", id, alias);
		g_debug("%s:%d->scrolled_box add:%s\n", __FILE__, __LINE__, buf);
		button = gtk_button_new_with_label(buf);
		g_object_set_data(G_OBJECT(button), "peer_id", (void *)dup_id);
		gtk_container_add(GTK_CONTAINER(scrolled_box), GTK_WIDGET(button));
		g_signal_connect (button, "clicked", G_CALLBACK (msg_cb),
				user_data);
		gtk_widget_show(button);
	}
	goto err;
err:
  if (parser)
    g_object_unref (parser);
	return;
}
void print_hello_cb()
{
  g_debug("hello\n");
}
gpointer read_thread(gpointer user_data)
{
	int rc = 0, method = 0, status = 0;
	const char *id = NULL;
	ChatAppWindow *win;
	ChatAppWindowPrivate *priv;
	GSocketConnection *conn;
	GInputStream *istream;
	GSettings *settings;
	GError *error = NULL;
	gint nread;
	uint8_t msg[MSG_MAX] = {0};
  char *data = NULL;

	win = user_data;
	priv = chat_app_window_get_instance_private (win);
  settings = priv->settings;
	id = g_settings_get_string(settings, "id");

	conn = g_object_get_data(G_OBJECT(win), "conn");
	g_debug("%s[%d]conn%p\n", __FILE__, __LINE__, conn);
	istream = g_io_stream_get_input_stream (G_IO_STREAM (conn));
  //g_object_set_data(win, "status", &status);
	while (1) {
    if (!(g_object_get_data(G_OBJECT(win), "conn")))
      goto out;
		nread = g_input_stream_read(istream, msg, sizeof(msg) - 1,
				NULL, &error);
		if (error) {
			g_error("%s\n", error->message);
			goto out;
		}
		if (nread > 0) {
			g_print("++++:%s\n", msg);
			//msg_add(win, "peer", buf, nread, TRUE);
			rc = account_client_message_parse(msg, nread, &method, &status, NULL);
			if (!rc) {
        g_settings_set_int(settings, "status", status);
				if (status == ACCOUNT_STATUS_SUCCESS_SIGN) {
					data = account_client_get_contacts(id);
					conn_send(win, data, strlen(data)); 
				} else if (status == ACCOUNT_STATUS_SUCCESS_GET_CONTACTS) {
					data_scrolled_add(priv->scrolled_box, msg, nread, win);
					/*
	obj = account_client_get_contact_msg(id, peer_id);
	obj_str = json_object_get_string(obj);
	conn_send(win, obj_str, strlen(obj_str)); 
	*/
				} else if (status == ACCOUNT_STATUS_MSG_READ) {
          g_debug("read\n");
				} else if (status == ACCOUNT_STATUS_MSG_UNREAD) {
          g_debug("no read\n");
				} else {
				}
				gtk_label_set_text(GTK_LABEL(priv->notice),
						account_status[status]);
			}
			memset(msg, 0, sizeof(msg));
		}
	}
out:
	if (error) {
		g_print ("%s\n", error->message);
		g_error_free (error);
	}
	if (data)
		g_free(data);
	return NULL;
}
void *sign_in(void *conn, void *user_data)
{
  ChatAppWindow *win = NULL;
	ChatAppWindowPrivate *priv = NULL;
  char *data = NULL, *id = NULL, *pwd = NULL;

  win = user_data;
	priv = chat_app_window_get_instance_private (win);
  gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_CONNECTED);
  g_debug("%s[%d]conn:%p\n", __FILE__, __LINE__, conn);
  id = g_settings_get_string(priv->settings, "id");
  if (!id) {
    gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_NO_ID);
    goto out;
  }
  pwd = g_settings_get_string(priv->settings, "pwd");
  if (!pwd) {
    gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_NO_PWD);
    goto out;
  }
  //send
  data = account_client_sign_in(id, pwd);
  conn_send(win, data, strlen(data)); 
out:
  if (data)
    g_free(data);
  return NULL;
}
static void
chat_app_window_init (ChatAppWindow *win)
{
	ChatAppWindowPrivate *priv;
  GSettings *settings;
	const gchar *obj_str = NULL, *id = NULL, *pwd = NULL;
	char buf[1024] = {0}, *data = NULL;
  gpointer conn = NULL;

	priv = chat_app_window_get_instance_private (win);
	gtk_widget_init_template (GTK_WIDGET (win));
	priv->settings = g_settings_new ("org.gtk.app");
  settings = priv->settings;
  g_settings_set_int(settings, "status", ACCOUNT_STATUS_DISCONNECTED);
  gtk_label_set_text(GTK_LABEL(priv->notice),
      account_status_to_str(ACCOUNT_STATUS_DISCONNECTED));

	obj_str = g_settings_get_string(priv->settings, "network");
	if (!obj_str) {
		gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_NO_SERVER);
	}
	conn = server_connect(obj_str, win);
	if (conn) {
	//	g_object_set_data(G_OBJECT(win), "conn", conn);
		gtk_label_set_text(GTK_LABEL(priv->notice),
				CHAT_NOTICE_CONNECTED);
		g_debug("%s[%d]conn:%p\n", __FILE__, __LINE__, conn);
		id = g_settings_get_string(priv->settings, "id");
		if (!id) {
			gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_NO_ID);
			goto err;
		}
		pwd = g_settings_get_string(priv->settings, "pwd");
		if (!pwd) {
			gtk_label_set_text(GTK_LABEL(priv->notice), CHAT_NOTICE_NO_PWD);
			goto err;
		}
		//send
		data = account_client_sign_in(id, pwd);
		conn_send(win, data, strlen(data)); 
	} else {
		snprintf(buf, sizeof(buf), "%s:netwrok:%s", CHAT_NOTICE_DISCONNECTED, obj_str);
		gtk_label_set_text(GTK_LABEL(priv->notice), buf);
	//			CHAT_NOTICE_CONNECTED);
	}
	g_signal_connect (priv->null, "clicked", G_CALLBACK (null_cb), win);
err:
  if (data)
    g_free(data);
	return;
}

static void
chat_app_window_dispose (GObject *object)
{
  ChatAppWindow *win;
  ChatAppWindowPrivate *priv;

  win = CHAT_APP_WINDOW (object);
  priv = chat_app_window_get_instance_private (win);

  g_clear_object (&priv->settings);

  G_OBJECT_CLASS (chat_app_window_parent_class)->dispose (object);
}

static void
chat_app_window_class_init (ChatAppWindowClass *class)
{
	G_OBJECT_CLASS (class)->dispose = chat_app_window_dispose;

	gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
					       "/org/gtk/app/window.ui");
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			ChatAppWindow, null);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			ChatAppWindow, notice);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			ChatAppWindow, scrolled_box);
  /*
  g_object_class_install_property (G_OBJECT_CLASS (class), 122,//ARG_TEST_PROP,
    g_param_spec_int ("test-prop", "Test Prop", "Test property",
        0, 1, 0, G_PARAM_READWRITE));
        */
	/*
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			ChatAppWindow, stack);
	gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (class),
			ChatAppWindow, null);
			*/
}

ChatAppWindow *
chat_app_window_new (ChatApp *app)
{
  return g_object_new (CHAT_APP_WINDOW_TYPE, "application", app, NULL);
}

void
chat_app_window_open (ChatAppWindow *win,
                         GFile            *file)
{
  ChatAppWindowPrivate *priv;
  gchar *basename;
  GtkWidget *scrolled, *view;
  gchar *contents;
  gsize length;
  GtkTextBuffer *buffer;
  GtkTextTag *tag;
  GtkTextIter start_iter, end_iter;

  priv = chat_app_window_get_instance_private (win);
  basename = g_file_get_basename (file);

  scrolled = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_show (scrolled);
  gtk_widget_set_hexpand (scrolled, TRUE);
  gtk_widget_set_vexpand (scrolled, TRUE);
  view = gtk_text_view_new ();
  gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
  gtk_widget_show (view);
  gtk_container_add (GTK_CONTAINER (scrolled), view);
  gtk_stack_add_titled (GTK_STACK (priv->stack), scrolled, basename, basename);

  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));

  if (g_file_load_contents (file, NULL, &contents, &length, NULL, NULL))
    {
      gtk_text_buffer_set_text (buffer, contents, length);
      g_free (contents);
    }

  tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
  g_settings_bind (priv->settings, "font",
                   tag, "font",
                   G_SETTINGS_BIND_DEFAULT);

  gtk_text_buffer_get_start_iter (buffer, &start_iter);
  gtk_text_buffer_get_end_iter (buffer, &end_iter);
  gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);

  g_free (basename);

  gtk_widget_set_sensitive (priv->search, TRUE);

}
